<template><div><h2 id="laravel-sanctum" tabindex="-1"><a class="header-anchor" href="#laravel-sanctum"><span>Laravel Sanctum</span></a></h2>
<ul>
<li><a href="#introduction">介绍</a>
<ul>
<li><a href="#how-it-works">工作原理</a></li>
</ul>
</li>
<li><a href="#installation">安装</a></li>
<li><a href="#configuration">配置</a>
<ul>
<li><a href="#overriding-default-models">覆盖默认模型</a></li>
</ul>
</li>
<li><a href="#api-token-authentication">API 令牌认证</a>
<ul>
<li><a href="#issuing-api-tokens">发出 API 令牌</a></li>
<li><a href="#token-abilities">令牌权限</a></li>
<li><a href="#protecting-routes">保护路由</a></li>
<li><a href="#revoking-tokens">吊销令牌</a></li>
<li><a href="#token-expiration">令牌过期</a></li>
</ul>
</li>
<li><a href="#spa-authentication">SPA 认证</a>
<ul>
<li><a href="#spa-configuration">配置</a></li>
<li><a href="#spa-authenticating">认证</a></li>
<li><a href="#protecting-spa-routes">保护路由</a></li>
<li><a href="#authorizing-private-broadcast-channels">授权私有广播频道</a></li>
</ul>
</li>
<li><a href="#mobile-application-authentication">移动应用程序认证</a>
<ul>
<li><a href="#issuing-mobile-api-tokens">发出 API 令牌</a></li>
<li><a href="#protecting-mobile-api-routes">保护路由</a></li>
<li><a href="#revoking-mobile-api-tokens">吊销令牌</a></li>
</ul>
</li>
<li><a href="#testing">测试</a></li>
</ul>
<h2 id="介绍" tabindex="-1"><a class="header-anchor" href="#介绍"><span>介绍</span></a></h2>
<p><a href="https://github.com/laravel/sanctum" target="_blank" rel="noopener noreferrer">Laravel Sanctum</a> 提供了一个轻量级的认证系统，可用于 SPA（单页应用程序）、移动应用程序和基于简单令牌的 API。Sanctum 允许的应用程序中的每个用户为他们的账户生成多个 API 令牌。这些令牌可以被授予权限/范围，以指定令牌允许执行哪些操作。</p>
<h3 id="工作原理" tabindex="-1"><a class="header-anchor" href="#工作原理"><span>工作原理</span></a></h3>
<p>Laravel Sanctum 旨在解决两个不同的问题。在深入探讨该库之前，让我们先讨论一下每个问题。</p>
<h4 id="api-令牌" tabindex="-1"><a class="header-anchor" href="#api-令牌"><span>API 令牌</span></a></h4>
<p>首先，Sanctum 是一个简单的包，你可以使用它向你的用户发出 API 令牌，而无需 OAuth 的复杂性。这个功能受到 GitHub 和其他应用程序发出「访问令牌」的启发。例如，假如你的应用程序的「账户设置」有一个界面，用户可以在其中为他们的账户生成 API 令牌。你可以使用 Sanctum 生成和管理这些令牌。这些令牌通常具有非常长的过期时间（以年计），但用户可以随时手动撤销它们。</p>
<p>Laravel Sanctum 通过将用户 API 令牌存储在单个数据库表中，并通过应该包含有效 API 令牌的 <code v-pre>Authorization</code> 标头对传入的 HTTP 请求进行身份验证来提供此功能。</p>
<h4 id="spa-认证" tabindex="-1"><a class="header-anchor" href="#spa-认证"><span>SPA 认证</span></a></h4>
<p>第二个功能，Sanctum 存在的目的是为需要与 Laravel 支持的 API 通信的单页应用程序 (SPAs) 提供一种简单的身份验证方式。这些 SPAs 可能存在于与 Laravel 应用程序相同的存储库中，也可能是一个完全独立的存储库，例如使用 Vue CLI 创建的 SPA 或 Next.js 应用程序。</p>
<p>对于此功能，Sanctum 不使用任何类型的令牌。相反，Sanctum 使用 Laravel 内置基于 cookie 的会话身份验证服务。通常，Sanctum 使用 Laravel 的 <code v-pre>web</code> 认证保护方式实现这一点。这提供了 CSRF 保护、会话身份验证以及防止通过 XSS 泄漏身份验证凭据的好处。</p>
<p>只有在传入请求来自你自己的 SPA 前端时，Sanctum 才会尝试使用 cookies 进行身份验证。当 Sanctum 检查传入的 HTTP 请求时，它首先会检查身份验证 cookie，如果不存在，则 Sanctum 会检查 <code v-pre>Authorization</code> 标头是否包含有效的 API 令牌。</p>
<blockquote>
<p><strong>注意</strong><br>
完全可以只使用 Sanctum 进行 API 令牌身份验证或只使用 Sanctuary 进行 SPA 身份验证。仅因为你使用 Sanctum 并不意味着你必须使用它提供的两个功能。</p>
</blockquote>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<blockquote>
<p><strong>注意</strong><br>
最近的 Laravel 版本已经包括 Laravel Sanctum。但如果你的应用程序的 <code v-pre>composer.json</code> 文件不包括 <code v-pre>laravel/sanctum</code>，你可以遵循下面的安装说明。</p>
</blockquote>
<p>你可以通过 Composer 包管理器安装 Laravel Sanctum：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require laravel/sanctum</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，你应该使用 <code v-pre>vendor:publish</code> Artisan 命令发布 Sanctum 配置文件和迁移文件。<code v-pre>sanctum</code> 配置文件将被放置在你的应用程序的 <code v-pre>config</code> 目录中：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan vendor:publish <span class="token parameter variable">--provider</span><span class="token operator">=</span><span class="token string">"Laravel\Sanctum\SanctumServiceProvider"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>最后，你应该运行数据库迁移。Sanctum 会创建一个数据库表来存储 API 令牌：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，如果你打算使用 Sanctum 来对 SPA 单页应用程序进行认证，则应该将 Sanctum 的中间件添加到你的应用程序的 <code v-pre>app/Http/Kernel.php</code> 文件中的 <code v-pre>api</code> 中间件组中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'api'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">   <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EnsureFrontendRequestsAreStateful</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">   <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Routing<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottleRequests</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token operator">.</span><span class="token string single-quoted-string">':api'</span><span class="token punctuation">,</span></span>
<span class="line">   <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Routing<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>SubstituteBindings</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义迁移" tabindex="-1"><a class="header-anchor" href="#自定义迁移"><span>自定义迁移</span></a></h4>
<p>如果你不打算使用 Sanctum 的默认迁移文件，则应该在 <code v-pre>App\Providers\AppServiceProvider</code> 类的 <code v-pre>register</code> 方法中调用 <code v-pre>Sanctum::ignoreMigrations</code> 方法。你可以通过执行以下命令导出默认的迁移文件：<code v-pre>php artisan vendor:publish --tag=sanctum-migrations</code></p>
<h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<h3 id="覆盖默认模型" tabindex="-1"><a class="header-anchor" href="#覆盖默认模型"><span>覆盖默认模型</span></a></h3>
<p>虽然通常不需要，但你可以自由扩展 Sanctum 内部使用的 <code v-pre>PersonalAccessToken</code> 模型:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>PersonalAccessToken</span> <span class="token keyword">as</span> SanctumPersonalAccessToken<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PersonalAccessToken</span> <span class="token keyword">extends</span> <span class="token class-name">SanctumPersonalAccessToken</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>然后，你可以通过 Sanctum 提供的 <code v-pre>usePersonalAccessTokenModel</code> 方法来指示 Sanctum 使用你的自定义模型。通常，你应该在一个应用程序的服务提供者的 <code v-pre>boot</code> 方法中调用此方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>PersonalAccessToken</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>Sanctum</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 引导任何应用程序服务。</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Sanctum</span><span class="token operator">::</span><span class="token function">usePersonalAccessTokenModel</span><span class="token punctuation">(</span><span class="token class-name static-context">PersonalAccessToken</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="api-令牌认证" tabindex="-1"><a class="header-anchor" href="#api-令牌认证"><span>API 令牌认证</span></a></h2>
<blockquote>
<p><strong>注意</strong><br>
你不应该使用 API 令牌来认证你自己的第一方单页应用程序。而应该使用 Sanctum 内置的 <a href="#spa-authentication">SPA 身份验证功能</a>。</p>
</blockquote>
<h3 id="发行-api-令牌" tabindex="-1"><a class="header-anchor" href="#发行-api-令牌"><span>发行 API 令牌</span></a></h3>
<p>Sanctum 允许你发行 API 令牌/个人访问令牌，可用于对你的应用程序的 API 请求进行身份验证。使用 API 令牌发出请求时，应将令牌作为 <code v-pre>Bearer</code> 令牌包括在 <code v-pre>Authorization</code> 头中。</p>
<p>要开始为用户发行令牌，你的用户模型应该使用 <code v-pre>Laravel\Sanctum\HasApiTokens</code> trait：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>HasApiTokens</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">HasApiTokens</span><span class="token punctuation">,</span> HasFactory<span class="token punctuation">,</span> Notifiable<span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要发行令牌，你可以使用 <code v-pre>createToken</code> 方法。<code v-pre>createToken</code> 方法会返回一个 <code v-pre>Laravel\Sanctum\NewAccessToken</code> 实例。在将 API 令牌存储到数据库之前，令牌将使用 SHA-256 哈希进行哈希处理，但是你可以通过 <code v-pre>NewAccessToken</code> 实例的 <code v-pre>plainTextToken</code> 属性访问令牌的明文值。你应该在令牌被创建后立即将其值显示给用户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/tokens/create'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$token</span> <span class="token operator">=</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">createToken</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">token_name</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'token'</span> <span class="token operator">=></span> <span class="token variable">$token</span><span class="token operator">-></span><span class="token property">plainTextToken</span><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>HasApiTokens</code> trait 提供的 <code v-pre>tokens</code> Eloquent 关联来访问用户的所有令牌：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">tokens</span> <span class="token keyword">as</span> <span class="token variable">$token</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="令牌能力" tabindex="-1"><a class="header-anchor" href="#令牌能力"><span>令牌能力</span></a></h3>
<p>Sanctum 允许你为令牌分配「能力」 。能力的作用类似于 OAuth 的「Scope」 。你可以将一个字符串能力数组作为 <code v-pre>createToken</code> 方法的第二个参数传递：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createToken</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'token-name'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'server:update'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">plainTextToken</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>当处理由 Sanctum 验证的入站请求时，你可以使用 <code v-pre>tokenCan</code> 方法确定令牌是否具有给定的能力：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tokenCan</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'server:update'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="令牌能力中间件" tabindex="-1"><a class="header-anchor" href="#令牌能力中间件"><span>令牌能力中间件</span></a></h4>
<p>Sanctum 还包括两个中间件，可用于验证传入的请求是否使用授予了给定能力的令牌进行了身份验证。首先，请将以下中间件添加到应用程序的 <code v-pre>app/Http/Kernel.php</code> 文件的 <code v-pre>$middlewareAliases</code> 属性中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'abilities'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>CheckAbilities</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token string single-quoted-string">'ability'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>CheckForAnyAbility</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><p>可以将 <code v-pre>abilities</code> 中间件分配给路由，以验证传入请求的令牌是否具有所有列出的能力：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/orders'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 令牌具有「check-status」和「place-orders」能力...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'abilities:check-status,place-orders'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>可以将 <code v-pre>ability</code> 中间件分配给路由，以验证传入请求的令牌是否至少具有一个列出的能力：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/orders'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 令牌具有「check-status」或「place-orders」能力...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'ability:check-status,place-orders'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="第一方-ui-启动的请求" tabindex="-1"><a class="header-anchor" href="#第一方-ui-启动的请求"><span>第一方 UI 启动的请求</span></a></h4>
<p>为了方便起见，如果入站身份验证请求来自你的第一方 SPA ，并且你正在使用 Sanctum 内置的 <a href="#spa-authentication">SPA 认证</a>，<code v-pre>tokenCan</code> 方法将始终返回 <code v-pre>true</code>。</p>
<p>然而，这并不一定意味着你的应用程序必须允许用户执行该操作。通常，你的应用程序的<a href="https://learnku.com/docs/laravel/10.x/authorization#creating-policies" target="_blank" rel="noopener noreferrer">授权策略</a> 将确定是否已授予令牌执行能力的权限，并检查用户实例本身是否允许执行该操作。</p>
<p>例如，如果我们想象一个管理服务器的应用程序，这可能意味着检查令牌是否被授权更新服务器<strong>并且</strong>服务器属于用户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$server</span><span class="token operator">-></span><span class="token property">user_id</span> <span class="token operator">&amp;&amp;</span></span>
<span class="line">       <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">tokenCan</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'server:update'</span><span class="token punctuation">)</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><p>首先允许 <code v-pre>tokenCan</code> 方法被调用并始终为第一方 UI 启动的请求返回 <code v-pre>true</code> 可能看起来很奇怪。然而，能够始终假设 API 令牌可用并可通过 <code v-pre>tokenCan</code> 方法进行检查非常方便。通过采用这种方法，你可以始终在应用程序的授权策略中调用 <code v-pre>tokenCan</code> 方法，而不用再担心请求是从应用程序的 UI 触发还是由 API 的第三方使用者发起的。</p>
<h3 id="保护路由" tabindex="-1"><a class="header-anchor" href="#保护路由"><span>保护路由</span></a></h3>
<p>为了保护路由，使所有入站请求必须进行身份验证，你应该在你的 <code v-pre>routes/web.php</code> 和 <code v-pre>routes/api.php</code> 路由文件中，将 <code v-pre>sanctum</code> 认证守卫附加到受保护的路由上。如果该请求来自第三方，该守卫将确保传入的请求经过身份验证，要么是具有状态的 Cookie 身份验证请求，要么是包含有效的 API 令牌标头的请求。</p>
<p>你可能想知道我们为什么建议你使用 <code v-pre>sanctum</code> 守卫在应用程序的 <code v-pre>routes/web.php</code> 文件中对路由进行身份验证。请记住，Sanctum 首先将尝试使用 Laravel 的典型会话身份验证 cookie 对传入请求进行身份验证。如果该 cookie 不存在，则 Sanctum 将尝试使用请求的 <code v-pre>Authorization</code> 标头中的令牌来验证请求。此外，使用 Sanctum 对所有请求进行身份验证，确保我们可以始终在当前经过身份验证的用户实例上调用 <code v-pre>tokenCan</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="撤销令牌" tabindex="-1"><a class="header-anchor" href="#撤销令牌"><span>撤销令牌</span></a></h3>
<p>你可以通过使用 <code v-pre>Laravel\Sanctum\HasApiTokens</code> trait 提供的 <code v-pre>tokens</code> 关系，从数据库中删除它们来达到「撤销」令牌的目的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 撤销所有令牌...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 撤销用于验证当前请求的令牌...</span></span>
<span class="line"><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">currentAccessToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 撤销特定的令牌...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">,</span> <span class="token variable">$tokenId</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="令牌有效期" tabindex="-1"><a class="header-anchor" href="#令牌有效期"><span>令牌有效期</span></a></h3>
<p>默认情况下，Sanctum 令牌永不过期，并且只能通过<a href="#revoking-tokens">撤销令牌</a>进行无效化。但是，如果你想为你的应用程序 API 令牌配置过期时间，可以通过在应用程序的 <code v-pre>sanctum</code> 配置文件中定义的 <code v-pre>expiration</code> 配置选项进行配置。此配置选项定义发放的令牌被视为过期之前的分钟数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 365天后过期</span></span>
<span class="line"><span class="token string single-quoted-string">'expiration'</span> <span class="token operator">=></span> <span class="token number">525600</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你已为应用程序配置了令牌过期时间，你可能还希望<a href="https://learnku.com/docs/laravel/10.x/scheduling" target="_blank" rel="noopener noreferrer">任务调度</a>来删除应用程序过期的令牌。幸运的是，Sanctum 包括一个 <code v-pre>sanctum:prune-expired</code> Artisan 命令，你可以使用它来完成此操作。例如，你可以配置计划任务来删除所有过期至少24小时的令牌数据库记录：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$schedule</span><span class="token operator">-></span><span class="token function">command</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'sanctum:prune-expired --hours=24'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">daily</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="spa-身份验证" tabindex="-1"><a class="header-anchor" href="#spa-身份验证"><span>SPA 身份验证</span></a></h2>
<p>Sanctum 还提供一种简单的方法来验证需要与 Laravel API 通信的单页面应用程序（SPA）。这些 SPA 可能存在于与你的 Laravel 应用程序相同的存储库中，也可能是一个完全独立的存储库。</p>
<p>对于此功能，Sanctum 不使用任何类型的令牌。相反，Sanctum 使用 Laravel 内置的基于 cookie 的 session 身份验证服务。此身份验证方法提供了 CSRF 保护、session 身份验证以及防止身份验证凭据通过 XSS 泄漏的好处。</p>
<blockquote>
<p><strong>警告</strong><br>
为了进行身份验证，你的 SPA 和 API 必须共享相同的顶级域。但是，它们可以放置在不同的子域中。此外，你应该确保你的请求中发送 <code v-pre>Accept: application/json</code> 头文件。</p>
</blockquote>
<h3 id="配置-1" tabindex="-1"><a class="header-anchor" href="#配置-1"><span>配置</span></a></h3>
<h4 id="配置你的第一个域" tabindex="-1"><a class="header-anchor" href="#配置你的第一个域"><span>配置你的第一个域</span></a></h4>
<p>首先，你应该通过 <code v-pre>sanctum</code> 配置文件中的 <code v-pre>stateful</code> 配置选项来配置你的 SPA 将从哪些域发出请求。此配置设置确定哪些域将在向你的 API 发送请求时使用 Laravel session cookie 维护「有状态的」身份验证。</p>
<blockquote>
<p><strong>警告</strong><br>
如果你通过包含端口的 URL（<code v-pre>127.0.0.1:8000</code>）访问应用程序，你应该确保在域名中包括端口号。</p>
</blockquote>
<h4 id="sanctum-中间件" tabindex="-1"><a class="header-anchor" href="#sanctum-中间件"><span>Sanctum 中间件</span></a></h4>
<p>接下来，你应该将 Sanctum 中间件添加到你的 <code v-pre>app/Http/Kernel.php</code> 文件中的 <code v-pre>api</code> 中间件组中。此中间件负责确保来自你的 SPA 的传入请求可以使用 Laravel 会话 cookie 进行身份验证，同时仍允许来自第三方或移动应用程序使用 API 令牌进行身份验证：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'api'</span> <span class="token operator">=></span> <span class="token punctuation">[</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EnsureFrontendRequestsAreStateful</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">   <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Routing<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>ThrottleRequests</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token operator">.</span><span class="token string single-quoted-string">':api'</span><span class="token punctuation">,</span></span>
<span class="line">   <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Routing<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>SubstituteBindings</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="cors-和-cookies" tabindex="-1"><a class="header-anchor" href="#cors-和-cookies"><span>CORS 和 Cookies</span></a></h4>
<p>如果你无法从执行在单独子域上的 SPA 中进行应用程序身份验证的话，你可能已错误配置了 CORS（跨域资源共享）或会话 cookie 设置。</p>
<p>你应该确保你的应用程序的 CORS 配置返回的 <code v-pre>Access-Control-Allow-Credentials</code> 请求头的值为 <code v-pre>True</code> 。这可以通过在应用程序的 <code v-pre>config/cors.php</code> 配置文件中设置 <code v-pre>supports_credentials</code> 选项为 <code v-pre>true</code> 来完成。</p>
<p>此外，你应该在应用程序的全局 <code v-pre>axios</code> 实例中启用 <code v-pre>withCredentials</code> 选项。通常，这应该在你的 <code v-pre>resources/js/bootstrap.js</code> 文件中进行。如果你没有使用 Axios 从前端进行 HTTP 请求，你应该使用自己的 HTTP 客户端进行等效配置：</p>
<div class="language-javascript line-numbers-mode" data-highlighter="prismjs" data-ext="js" data-title="js"><pre v-pre class="language-javascript"><code><span class="line">axios<span class="token punctuation">.</span>defaults<span class="token punctuation">.</span>withCredentials <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">axios<span class="token punctuation">.</span>defaults<span class="token punctuation">.</span>withXSRFToken  <span class="token operator">=</span>  <span class="token boolean">true</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><p>最后，你应该确保应用程序的会话 cookie 域配置支持根域的任何子域。你可以通过在应用程序的 <code v-pre>config/session.php</code> 配置文件中使用前导 <code v-pre>.</code> 作为域的前缀来实现此目的：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'domain'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'.domain.com'</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="身份验证" tabindex="-1"><a class="header-anchor" href="#身份验证"><span>身份验证</span></a></h3>
<h4 id="csrf-保护" tabindex="-1"><a class="header-anchor" href="#csrf-保护"><span>CSRF 保护</span></a></h4>
<p>要验证你的 SPA，你的 SPA 的「登录」页面应首先向 <code v-pre>/sanctum/csrf-cookie</code> 发出请求以初始化应用程序的 CSRF 保护：</p>
<div class="language-javascript line-numbers-mode" data-highlighter="prismjs" data-ext="js" data-title="js"><pre v-pre class="language-javascript"><code><span class="line">axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/sanctum/csrf-cookie'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// Login...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在此请求期间，Laravel 将设置一个包含当前 CSRF 令牌的 <code v-pre>XSRF-TOKEN</code> cookie。然后，此令牌应在随后的请求中通过 <code v-pre>X-XSRF-TOKEN</code> 标头传递，其中某些 HTTP 客户端库（如 Axios 和 Angular HttpClient）将自动为你执行此操作。如果你的 JavaScript HTTP 库没有为你设置值，你将需要手动设置 <code v-pre>X-XSRF-TOKEN</code> 请求头以匹配此路由设置的 <code v-pre>XSRF-TOKEN</code> cookie 的值。</p>
<h4 id="登录" tabindex="-1"><a class="header-anchor" href="#登录"><span>登录</span></a></h4>
<p>一旦已经初始化了 CSRF 保护，你应该向 Laravel 应用程序的 <code v-pre>/login</code> 路由发出 <code v-pre>POST</code> 请求。这个 <code v-pre>/login</code> 路由可以通过<a href="https://learnku.com/docs/laravel/10.x/authentication#authenticating-users" target="_blank" rel="noopener noreferrer">手动实现</a>或使用像 <a href="https://learnku.com/docs/laravel/10.x/fortify" target="_blank" rel="noopener noreferrer">Laravel Fortify</a> 这样的无请求头身份验证包来实现。</p>
<p>如果登录请求成功，你将被验证，随后对应用程序路由的后续请求将通过 Laravel 应用程序发出的会话 cookie 自动进行身份验证。此外，由于你的应用程序已经发出了对 <code v-pre>/sanctum/csrf-cookie</code> 路由的请求，因此只要你的 JavaScript HTTP 客户端在 <code v-pre>X-XSRF-TOKEN</code> 标头中发送了 <code v-pre>XSRF-TOKEN</code> cookie 的值，后续的请求应该自动接受 CSRF 保护。</p>
<p>当然，如果你的用户会话因缺乏活动而过期，那么对 Laravel 应用程序的后续请求可能会收到 401 或 419 HTTP 错误响应。在这种情况下，你应该将用户重定向到你 SPA 的登录页面。</p>
<blockquote>
<p><strong>警告</strong><br>
你可以自己编写 <code v-pre>/login</code> 端点；但是，你应该确保使用 Laravel 提供的标准基于<a href="https://learnku.com/docs/laravel/10.x/authentication#authenticating-users" target="_blank" rel="noopener noreferrer">会话的身份验证服务</a>来验证用户。通常，这意味着使用 <code v-pre>web</code> 身份验证 Guard。</p>
</blockquote>
<h3 id="保护路由-1" tabindex="-1"><a class="header-anchor" href="#保护路由-1"><span>保护路由</span></a></h3>
<p>为了保护路由，以便所有传入的请求必须进行身份验证，你应该将 <code v-pre>sanctum</code> 身份验证 guard 附加到 <code v-pre>routes/api.php</code> 文件中的 API 路由上。这个 guard 将确保传入的请求被验证为来自你的 SPA 的有状态身份验证请求，或者如果请求来自第三方，则包含有效的 API 令牌标头：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="授权私有广播频道" tabindex="-1"><a class="header-anchor" href="#授权私有广播频道"><span>授权私有广播频道</span></a></h3>
<p>如果你的 SPA 需要对<a href="https://learnku.com/docs/laravel/10.x/broadcasting#authorizing-channels" target="_blank" rel="noopener noreferrer">私有/存在 broadcast 频道进行身份验证</a>，你应该在 <code v-pre>routes/api.php</code> 文件中调用 <code v-pre>Broadcast::routes</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Broadcast</span><span class="token operator">::</span><span class="token function">routes</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'middleware'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，为了让 Pusher 的授权请求成功，你需要在初始化 <a href="https://learnku.com/docs/laravel/10.x/broadcasting#client-side-installation" target="_blank" rel="noopener noreferrer">Laravel Echo</a> 时提供自定义的 Pusher <code v-pre>authorizer</code>。这允许你的应用程序配置 Pusher 以使用<a href="#cors-and-cookies">为跨域请求正确配置的</a> <code v-pre>axios</code> 实例：</p>
<div class="language-javascript line-numbers-mode" data-highlighter="prismjs" data-ext="js" data-title="js"><pre v-pre class="language-javascript"><code><span class="line">window<span class="token punctuation">.</span>Echo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Echo</span><span class="token punctuation">(</span><span class="token punctuation">{</span></span>
<span class="line">    <span class="token literal-property property">broadcaster</span><span class="token operator">:</span> <span class="token string">"pusher"</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token literal-property property">cluster</span><span class="token operator">:</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">VITE_PUSHER_APP_CLUSTER</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token literal-property property">encrypted</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token literal-property property">key</span><span class="token operator">:</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">VITE_PUSHER_APP_KEY</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token function-variable function">authorizer</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">channel<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function-variable function">authorize</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">socketId<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">                axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">'/api/broadcasting/auth'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span></span>
<span class="line">                    <span class="token literal-property property">socket_id</span><span class="token operator">:</span> socketId<span class="token punctuation">,</span></span>
<span class="line">                    <span class="token literal-property property">channel_name</span><span class="token operator">:</span> channel<span class="token punctuation">.</span>name</span>
<span class="line">                <span class="token punctuation">}</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">                    <span class="token function">callback</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> response<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">                <span class="token punctuation">}</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">error</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span>
<span class="line">                    <span class="token function">callback</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">            <span class="token punctuation">}</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="移动应用程序身份验证" tabindex="-1"><a class="header-anchor" href="#移动应用程序身份验证"><span>移动应用程序身份验证</span></a></h2>
<p>你也可以使用 Sanctum 令牌来验证你的移动应用程序对 API 的请求。验证移动应用程序请求的过程类似于验证第三方 API 请求；但是，你将发布 API 令牌的方式有所不同。</p>
<h3 id="发布-api-令牌" tabindex="-1"><a class="header-anchor" href="#发布-api-令牌"><span>发布 API 令牌</span></a></h3>
<p>首先，请创建一个路由，该路由接受用户的电子邮件/用户名、密码和设备名称，然后将这些凭据交换为新的 Sanctum 令牌。给此端点提供「设备名称」的目的是为了记录信息，仅供参考。通常来说，设备名称值应该是用户能够识别的名称，例如「Nuno’s iPhone 12」。</p>
<p>通常，你将从你的移动应用程序的「登录」页面向令牌端点发出请求。此端点将返回纯文本的 API 令牌，可以存储在移动设备上，并用于进行额外的 API 请求：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Hash</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Validation<span class="token punctuation">\</span>ValidationException</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/sanctum/token'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">validate</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required|email'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'password'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'device_name'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'required'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'email'</span><span class="token punctuation">,</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token property">email</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token variable">$user</span> <span class="token operator">||</span> <span class="token operator">!</span> <span class="token class-name static-context">Hash</span><span class="token operator">::</span><span class="token function">check</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">password</span><span class="token punctuation">,</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">password</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">throw</span> <span class="token class-name static-context">ValidationException</span><span class="token operator">::</span><span class="token function">withMessages</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'email'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'The provided credentials are incorrect.'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">createToken</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token property">device_name</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token property">plainTextToken</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当移动应用程序使用令牌向你的应用程序发出 API 请求时，它应该将令牌作为 <code v-pre>Bearer</code> 令牌放在 <code v-pre>Authorization</code> 标头中传递。</p>
<blockquote>
<p><strong>注意</strong><br>
当为移动应用程序发布令牌时，你可以自由指定<a href="#token-abilities">令牌权限</a>。</p>
</blockquote>
<h3 id="路由保护" tabindex="-1"><a class="header-anchor" href="#路由保护"><span>路由保护</span></a></h3>
<p>如之前所述，你可以通过使用 <code v-pre>sanctum</code> 认证守卫附加到路由上来保护路由，以便所有传入请求都必须进行身份验证：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth:sanctum'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/user'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="撤销令牌-1" tabindex="-1"><a class="header-anchor" href="#撤销令牌-1"><span>撤销令牌</span></a></h3>
<p>为了允许用户撤销发放给移动设备的 API 令牌，你可以在 Web 应用程序 UI 的 「帐户设置」部分中按名称列出它们，并提供一个「撤销」按钮。当用户点击「撤销」按钮时，你可以从数据库中删除令牌。请记住，你可以通过 <code v-pre>Laravel\Sanctum\HasApiTokens</code> 特性提供的 <code v-pre>tokens</code> 关系访问用户的 API 令牌：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 撤销所有令牌...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 撤销特定令牌...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">tokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">where</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'id'</span><span class="token punctuation">,</span> <span class="token variable">$tokenId</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="测试" tabindex="-1"><a class="header-anchor" href="#测试"><span>测试</span></a></h2>
<p>在测试时，<code v-pre>Sanctum::actingAs</code> 方法可用于验证用户并指定为其令牌授予哪些能力：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Sanctum<span class="token punctuation">\</span>Sanctum</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_task_list_can_be_retrieved</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Sanctum</span><span class="token operator">::</span><span class="token function">actingAs</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">factory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">[</span><span class="token string single-quoted-string">'view-tasks'</span><span class="token punctuation">]</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/api/task'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">assertOk</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想授予令牌所有的能力，你应该在提供给 <code v-pre>actingAs</code> 方法的能力列表中包含 <code v-pre>*</code> ：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Sanctum</span><span class="token operator">::</span><span class="token function">actingAs</span><span class="token punctuation">(</span></span>
<span class="line">    <span class="token class-name static-context">User</span><span class="token operator">::</span><span class="token function">factory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">[</span><span class="token string single-quoted-string">'*'</span><span class="token punctuation">]</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/10.x/sanctum/14914" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/10.x/sa...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/10.x/sanctum/14914" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/10.x/sa...</a></p>
</blockquote>
</div></template>


